package com.dimples.dd.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dimples.dd.common.constant.DDConstant;
import com.dimples.dd.common.pojo.PageResult;
import com.dimples.dd.redis.core.RedisHelper;
import com.dimples.dd.redis.core.constant.RedisConstants;
import com.dimples.dd.system.convert.GatewayRouteConvert;
import com.dimples.dd.system.mapper.SystemGatewayRouteMapper;
import com.dimples.dd.system.model.entity.SystemGatewayRouteDO;
import com.dimples.dd.system.model.form.GatewayRouteForm;
import com.dimples.dd.system.model.query.GatewayRoutePageQuery;
import com.dimples.dd.system.model.vo.GatewayRoutePageVO;
import com.dimples.dd.system.service.SystemGatewayRouteService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

import static com.dimples.dd.common.exception.BizExceptionUtil.exception;
import static com.dimples.dd.common.exception.ErrorCode.GATEWAY_ROUTE_EXISTS;
import static com.dimples.dd.common.exception.ErrorCode.GATEWAY_ROUTE_NOT_EXISTS;

@Slf4j
@Service
@RequiredArgsConstructor
public class SystemGatewayRouteServiceImpl extends ServiceImpl<SystemGatewayRouteMapper, SystemGatewayRouteDO> implements SystemGatewayRouteService {

    private final GatewayRouteConvert gatewayRouteConvert;

    private final RedisHelper redisHelper;

    @Override
    public void addRoute2Redis(String key) {
        this.redisHelper.set(key, JSONUtil.toJsonStr(this.list()));
    }

    @Override
    public void clearRedis() {
        this.redisHelper.set(RedisConstants.GATEWAY_ROUTES, null);
    }

    @Override
    public Long createGatewayRoute(GatewayRouteForm gatewayRouteForm) {
        // 1. 校验网关路由
        validateGatewayRouteForUpdate(null, gatewayRouteForm.getRouterId());

        // 2. 插入到数据库
        try {
            SystemGatewayRouteDO gatewayRoute = this.gatewayRouteConvert.form2Entity(gatewayRouteForm);
            this.baseMapper.insert(gatewayRoute);

            // 3. 刷新缓存
            this.refreshRouter(null);
            return gatewayRoute.getId();
        } catch (Exception e) {
            refreshRouter(null);
        }
        return 0L;
    }

    /**
     * 更新redis路由缓存
     *
     * @param delRouterId 删除的路由ID
     */
    private void refreshRouter(String delRouterId) {
        log.info(DDConstant.CONFIG_LOG, "更新redis路由缓存");
        //更新redis路由缓存
        addRoute2Redis(RedisConstants.GATEWAY_ROUTES);
        Map<String, Object> params = MapUtil.newHashMap();
        params.put(RedisConstants.HANDLER_NAME, RedisConstants.LOADER_ROUTER_HANDLER);
        params.put(RedisConstants.ROUTE_MESSAGE_DELETE_ROUTER_ID, delRouterId);
        //刷新网关
        this.redisHelper.convertAndSend(RedisConstants.REDIS_TOPIC_NAME, params);
    }

    private void validateGatewayRouteForUpdate(Long id, String routerId) {
        List<SystemGatewayRouteDO> gatewayRoutes = this.baseMapper.selectList(SystemGatewayRouteDO::getRouterId, routerId);

        if (id != null) {
            // 判断是否存在routerId
            if (CollUtil.isEmpty(gatewayRoutes)) {
                throw exception(GATEWAY_ROUTE_NOT_EXISTS, routerId);
            }
        } else {
            // 判断是否存在routerId
            if (CollUtil.size(gatewayRoutes) > 0) {
                throw exception(GATEWAY_ROUTE_EXISTS, routerId);
            }
        }
    }

    @Override
    public void updateGatewayRoute(GatewayRouteForm gatewayRouteForm) {
        validateGatewayRouteForUpdate(gatewayRouteForm.getId(), gatewayRouteForm.getRouterId());

        SystemGatewayRouteDO gatewayRoute = this.gatewayRouteConvert.form2Entity(gatewayRouteForm);
        this.baseMapper.updateById(gatewayRoute);
        // 刷新缓存
        this.refreshRouter(null);
    }

    @Override
    public void deleteGatewayRoute(Long id) {
        SystemGatewayRouteDO gatewayRouteDO = this.baseMapper.selectById(id);
        this.baseMapper.deleteById(id);
        this.refreshRouter(gatewayRouteDO.getRouterId());
    }

    @Override
    public GatewayRouteForm selectGatewayRoute(Long id) {
        SystemGatewayRouteDO gatewayRouteDO = this.baseMapper.selectById(id);
        return this.gatewayRouteConvert.entity2Form(gatewayRouteDO);
    }

    @Override
    public PageResult<GatewayRoutePageVO> selectGatewayRoutePage(GatewayRoutePageQuery pageQuery) {
        PageResult<SystemGatewayRouteDO> doPageResult = this.baseMapper.selectGatewayRoutePage(pageQuery);
        return this.gatewayRouteConvert.page2VO(doPageResult);
    }
}
